home *** CD-ROM | disk | FTP | other *** search
/ Aminet 39 / Aminet 39 (2000)(Schatztruhe)[!][Oct 2000].iso / Aminet / game / shoot / Orbit_src.lha / Orbit / source / network.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-07-04  |  19.7 KB  |  1,077 lines

  1. /*
  2.     Amiga port by Oliver Gantert
  3.  
  4.     27.04.2000 - fixed some compiler warnings, but many errors left
  5.     28.04.2000 - commented out some functions, no networking on Amiga yet
  6. */
  7. /* 
  8.  
  9. ORBIT, a freeware space combat simulator 
  10. Copyright (C) 1999  Steve Belczyk <steve1@genesis.nred.ma.us> 
  11.  
  12. This program is free software; you can redistribute it and/or 
  13. modify it under the terms of the GNU General Public License 
  14. as published by the Free Software Foundation; either version 2 
  15. of the License, or (at your option) any later version. 
  16.  
  17. This program is distributed in the hope that it will be useful, 
  18. but WITHOUT ANY WARRANTY; without even the implied warranty of 
  19. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  20. GNU General Public License for more details. 
  21.  
  22. You should have received a copy of the GNU General Public License 
  23. along with this program; if not, write to the Free Software 
  24. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. 
  25.  
  26. */ 
  27.  
  28. #include "orbit.h"
  29.  
  30. #ifndef AMIGA
  31. #ifndef WIN32
  32. #include <sys/socket.h>
  33. #include <unistd.h>
  34. #include <netinet/in.h>
  35. #include <netdb.h>
  36. #include <arpa/inet.h>
  37. #include <netinet/tcp.h>
  38. #endif /* WIN32 */
  39. #include <fcntl.h>
  40. #endif /* AMIGA */
  41.  
  42. #include <errno.h>
  43. #include <limits.h>
  44. #include <stdarg.h>
  45.  
  46. /*
  47.  *  All sorts of stuff for network communication
  48.  */
  49.  
  50. int endian; /* Endian for transmitting network values */
  51.  
  52. void InitNetwork()
  53. /*
  54.  *  Initialize network data structures
  55.  */
  56. {
  57.   int c;
  58.  
  59.   Log ("InitNetwork: Initializing network");
  60.  
  61.   am_server = 0;
  62.   am_client = 0;
  63.  
  64.   recv_bytes = xmit_bytes = 0;
  65.  
  66.   for (c=0; c<NCLIENTS; c++)
  67.   {
  68.     client[c].active = 0;
  69.     client[c].is_me = 0;
  70.     client[c].ping = 0.0;
  71.     client[c].target = (-1);
  72.     client[c].frags = 0;
  73.     client[c].ip[0] = 0;
  74.  
  75.     client[c].timer.idle = 0.0;
  76.     client[c].timer.ping = 0.0;
  77.  
  78.     client[c].state = NETSTATE_MAGIC;
  79.   }
  80. }
  81.  
  82. int OpenNetwork()
  83. /*
  84.  *  Really only need this for Winsock
  85.  */
  86. {
  87.   #ifdef WIN32
  88.   WSADATA wsadata;
  89.   #endif
  90.  
  91.   Log ("OpenNetwork: Opening network");
  92.  
  93.   #ifdef WIN32
  94.   if (SOCKET_ERROR == WSAStartup (0x202, &wsadata))
  95.   {
  96.     Log ("OpenNetwork: WSAStartup failed with error %d",
  97.     WSAGetLastError());
  98.     WSACleanup();
  99.     return 0;
  100.   }
  101.   #endif
  102.  
  103.   return 1;
  104. }
  105.  
  106. void CloseNetwork()
  107. /*
  108.  *  Close Winsock
  109.  */
  110. {
  111.   Log ("CloseNetwork: Closing network");
  112.  
  113.   #ifdef WIN32
  114.   WSACleanup();
  115.   #endif
  116. }
  117.  
  118. int BecomeServer()
  119. /*
  120.  *  Become an ORBIT server
  121.  */
  122. {
  123.   #ifndef AMIGA
  124.   struct sockaddr_in address;
  125.   SOCKET listening_socket;
  126.   int one = 1;
  127.   int b, t, c;
  128.  
  129.   Cprint ("Becoming ORBIT server...");
  130.   Log ("BecomeServer: Becoming ORBIT server...");
  131.  
  132.   /* Determine how to send floats */
  133.   if (!FindEndian()) return 0;
  134.  
  135.   /* Open Winsock */
  136.   if (!OpenNetwork()) return 0;
  137.  
  138.   /* Set address and port to listen on */
  139.   memset ((char *) &address, 0, sizeof(address));
  140.   address.sin_family = AF_INET;
  141.   address.sin_port = htons (server.port);
  142.   address.sin_addr.s_addr = htonl (INADDR_ANY);
  143.  
  144.   /* Create the socket.  This shouldn't cause any network activity;
  145.     it's just creating a kernel data structure */
  146.   Log ("BecomeServer: creating listening socket");
  147.   listening_socket = socket (AF_INET, SOCK_STREAM, 0);
  148.   if (listening_socket < 0)
  149.   {
  150.     Log ("BecomeServer: socket returned %d", listening_socket);
  151.     CloseNetwork();
  152.     return 0;
  153.   }
  154.  
  155.   /* Remember listening socket so we can close it later */
  156.   server.listening_socket = listening_socket;
  157.  
  158.   /* Set the listening socket option SO_REUSEADDR. */
  159.   setsockopt (listening_socket, SOL_SOCKET, SO_REUSEADDR, (char *) &one,
  160.   sizeof(one));
  161.  
  162.   /* Bind the listening socket to the address information */
  163.   b = bind (listening_socket, (struct sockaddr *) &address, sizeof(address));
  164.   if (b < 0)
  165.   {
  166.     Log ("BecomeServer: bind() returned %d", b);
  167.     #ifndef WIN32
  168.     close (listening_socket);
  169.     #else
  170.     closesocket (listening_socket);
  171.     #endif
  172.     CloseNetwork();
  173.     return 0;
  174.   }
  175.  
  176.   /* Set number of connections to queue */
  177.   listen (listening_socket, 3);
  178.  
  179.   /* Put the socket in non-blocking mode so we can poll it
  180.     (This should really be done by getting the flags and setting
  181.     the one bit) */
  182.   #ifdef WIN32
  183.   ioctlsocket (listening_socket, FIONBIO, &one);
  184.   #else
  185.   fcntl (listening_socket, F_SETFL, O_NONBLOCK);
  186.   #endif
  187.  
  188.   /* Remember I'm a server */
  189.   am_server = 1; 
  190.   
  191.   /* Save IP address? */ 
  192.   strcpy (server.ip, inet_ntoa(address.sin_addr));
  193.  
  194.   Cprint ("Now an ORBIT server, listening on port %d", server.port);
  195.   Log ("BecomeServer: Successfully became server");
  196.  
  197.   /* Reset targets, events, weapons and planets, etc; */
  198.   InitTargets();
  199.   ResetEvents();
  200.   InitWeapons();
  201.   ResetPlanets();
  202.   InitWaypoints();
  203.   ResetModels();
  204.   lock.target = (-1); 
  205.   compression = 1.0;
  206.  
  207.   /* Network players are always vulnerable */
  208.   vulnerable = 1;
  209.  
  210.   /* Set up a client and target for me */
  211.   c = FindClient();
  212.   client[c].active = 1;
  213.   client[c].is_me = 1;
  214.   server.client = c;
  215.   t = client[c].target = InitClientTarget();
  216.   strcpy (target[t].name, player.name);
  217.   target[t].hidden = target[t].invisible = 1;
  218.  
  219.   return 1;
  220.   #else
  221.   return 0;
  222.   #endif /* AMIGA */
  223. }
  224.  
  225. int BecomeClient (char *s)
  226. /*
  227.  *  Try to become ORBIT client
  228.  */
  229. {
  230.   #ifndef AMIGA
  231.   /* struct in_addr *addr; */
  232.   SOCKET sock;
  233.   int c, port;
  234.   struct sockaddr_in address;
  235.   char ip[128];
  236.  
  237.   #ifdef WIN32
  238.   unsigned long one = 1;
  239.   #else
  240.   int one = 1;
  241.   #endif
  242.  
  243.   Log ("BecomeClient: Trying to become client");
  244.  
  245.   /* Determine how to send floats */
  246.   if (!FindEndian()) return 0;
  247.  
  248.   /* Parse address as ip[ port] */
  249.   port = (-1);
  250.   sscanf (s, "%s %d", ip, &port);
  251.  
  252.   /* Init Winsock */
  253.   if (!OpenNetwork()) return 0;
  254.  
  255.   /* Set up address, port of server */
  256.   address.sin_family = AF_INET;
  257.   address.sin_port = htons ((port < 0) ? ORBIT_PORT : port);
  258.   address.sin_addr.s_addr = inet_addr (ip);
  259.  
  260.   /* Create the socket */
  261.   sock = socket (AF_INET, SOCK_STREAM, 0);
  262.   if (sock < 0)
  263.   {
  264.     Log ("BecomeClient: socket error: %d", errno);
  265.     CloseNetwork();
  266.     return 0;
  267.   }
  268.  
  269.   /* Connect to the server */
  270.   Log ("BecomeClient: Connecting to server %s on port %d...",
  271.   ip, (port < 0 ? ORBIT_PORT : port));
  272.   Cprint ("Connecting to server %s on port %d...",
  273.   ip, (port < 0 ? ORBIT_PORT : port));
  274.   c = connect (sock, (struct sockaddr *) &address, sizeof(address));
  275.  
  276.   /* Did it work? */
  277.   if (c < 0)
  278.   {
  279.     /* No */
  280.     Mprint ("Could not connect to server");
  281.     Log ("BecomeClient: connect() error: %d", errno);
  282.     CloseNetwork();
  283.     return 0;
  284.   }
  285.  
  286.   /* Yes!  We are connected */
  287.   Mprint ("Connected to server");
  288.   Log ("BecomeClient: Connected to server");
  289.  
  290.   /* Declare I am a client */
  291.   am_client = 1;
  292.  
  293.   /* Remember this socket */
  294.   clientme.socket = sock;
  295.  
  296.   /* Make the socket non-blocking */
  297.   #ifdef WIN32
  298.   ioctlsocket (clientme.socket, FIONBIO, &one);
  299.   #else
  300.   fcntl (clientme.socket, F_SETFL, O_NONBLOCK);
  301.   #endif
  302.  
  303.   /* Disable the Nagle algorithm */
  304.   setsockopt (clientme.socket, IPPROTO_TCP, TCP_NODELAY, (char *) &one,
  305.   sizeof(one));
  306.  
  307.   /* Init incoming packet buffer */
  308.   clientme.pkt[0] = 0;
  309.   clientme.ptr = 0;
  310.  
  311.   /* Init timers */
  312.   clientme.timer.pos = 0.0;
  313.   clientme.timer.server = 0.0;
  314.  
  315.   /* Init packet state */
  316.   clientme.state = NETSTATE_MAGIC;
  317.  
  318.   /* Send our name and model */
  319.   SendASCIIPacket (clientme.socket, "NAME %s\n", player.name);
  320.   SendASCIIPacket (clientme.socket, "MODL %s\n", player.model);
  321.   SendASCIIPacket (clientme.socket, "VERS %s\n", VERSION);
  322.  
  323.   /* Report our position */
  324.   ReportPosition();
  325.  
  326.   /* Network players are always vulnerable */
  327.   vulnerable = 1;
  328.  
  329.   /* Reset targets, events, weapons and planets, etc; */
  330.   InitTargets();
  331.   ResetEvents();
  332.   InitWeapons();
  333.   ResetPlanets();
  334.   InitWaypoints();
  335.   ResetModels();
  336.   lock.target = (-1); 
  337.   compression = 1.0;
  338.  
  339.   return 1;
  340.   #else
  341.   return 0;
  342.   #endif /* AMIGA */
  343. }
  344.  
  345. void DoNetwork()
  346. /*
  347.  *  Process network activity
  348.  */
  349. {
  350.   /* Are we client or server (or neither?) */
  351.   if (am_server) DoServer();
  352.   if (am_client) DoClient();
  353. }
  354.  
  355. void SendASCIIPacket (SOCKET socket, char *fmt, ...)
  356. /*
  357.  *  Write an ASCII packet to given network socket
  358.  */
  359. {
  360.   #ifndef AMIGA
  361.   va_list ap;
  362.   char buf[1024];
  363.   int len;
  364.   #ifndef BINARYPACKETS
  365.   int e;
  366.   #endif
  367.  
  368.   /* Start up varargs stuff */
  369.   va_start (ap, fmt);
  370.  
  371.   /* Get packet into string */
  372.   vsprintf (buf, fmt, ap);
  373.  
  374.   /* Wrap up varargs */
  375.   va_end (ap);
  376.  
  377.   /* Add trailing null */
  378.   buf[strlen(buf)] = 0;
  379.  
  380.   /* Send it */
  381.   len = 1 + strlen (buf);
  382.   #ifdef BINARYPACKETS
  383.   XmitBinaryPacket (socket, buf, len);
  384.   #else
  385.   e = send (socket, buf, len, 0);
  386.   #endif
  387.   xmit_bytes += len;
  388.   #endif /* AMIGA */
  389. }
  390.  
  391. void XmitBinaryPacket (SOCKET socket, char *buf, int len)
  392. {
  393.   #ifndef AMIGA
  394.   char pkt[512];
  395.   int i;
  396.  
  397.   /* Length check */
  398.   if (len > 255)
  399.   {
  400.     Cprint ("PANIC: Packet too large: %d", len);
  401.     return;
  402.   }
  403.  
  404.   /* Put in magic byte */
  405.   pkt[0] = NET_MAGIC;
  406.  
  407.   /* Put in size */
  408.   pkt[1] = len;
  409.  
  410.   /* Put in data */
  411.   for (i=0; i<len; i++) pkt[2+i] = buf[i];
  412.  
  413.   /* Send it! */
  414.   send (socket, pkt, len+2, 0);
  415.   #endif /* AMIGA */
  416. }
  417.  
  418. void ShutdownClient()
  419. /*
  420.  *  Undo being a client
  421.  */
  422. {
  423.   #ifndef AMIGA
  424.   if (!am_client) return;
  425.  
  426.   Log ("ShutdownClient: Shutting down network client");
  427.  
  428.   /* Close the socket to the server */
  429.   #ifndef WIN32
  430.   close (clientme.socket);
  431.   #else
  432.   closesocket (clientme.socket);
  433.   #endif
  434.  
  435.   /* Shut down Winsock */
  436.   CloseNetwork();
  437.  
  438.   /* Show no longer client */
  439.   am_client = 0;
  440.  
  441.   /* Tell Sparky */
  442.   Mprint ("Disconnected from server");
  443.  
  444.   /* Reset network data structures */
  445.   InitNetwork();
  446.   InitTargets();
  447.   #endif /* AMIGA */
  448. }
  449.  
  450. void ShutdownServer()
  451. /*
  452.  *  Stop being a server
  453.  */
  454. {
  455.   #ifndef AMIGA
  456.   int c;
  457.  
  458.   if (!am_server) return;
  459.  
  460.   Log ("ShutdownServer: Shutting down network server");
  461.  
  462.   /* Close each active client connection */
  463.   for (c=0; c<NCLIENTS; c++)
  464.   {
  465.     if (client[c].active && (c != server.client))
  466.     {
  467.       Log ("ShutdownServer: Closing client %d", c);
  468.       DropClient (c);
  469.     }
  470.   }
  471.  
  472.   /* Stop listening for clients */
  473.   #ifndef WIN32
  474.   close (server.listening_socket);
  475.   #else
  476.   closesocket (server.listening_socket);
  477.   #endif
  478.  
  479.   /* Shut down Winsock */
  480.   CloseNetwork();
  481.  
  482.   /* No longer server */
  483.   am_server = 0;
  484.  
  485.   /* Hey Sparky */
  486.   Mprint ("No longer a server");
  487.  
  488.   /* Reset network data structures */
  489.   InitNetwork();
  490.   #endif /* AMIGA */
  491. }
  492.  
  493. void ShutdownNetwork()
  494. /*
  495.  *  Shut down all network connections and services
  496.  */
  497. {
  498.   Log ("ShutdownNetwork: Shutting down network");
  499.  
  500.   if (am_server) ShutdownServer();
  501.   if (am_client) ShutdownClient();
  502. }
  503.  
  504. void DropClient (int c)
  505. /*
  506.  *  Hang up on client c
  507.  */
  508. {
  509.   #ifndef AMIGA
  510.   int cc;
  511.   #ifndef WIN32
  512.   close (client[c].socket);
  513.   #else
  514.   closesocket (client[c].socket);
  515.   #endif
  516.  
  517.   client[c].active = 0;
  518.  
  519.   /* Notify us */
  520.   Cprint ("%s is gone", target[client[c].target].name);
  521.  
  522.   /* Notify everyone */
  523.   for (cc=0; cc<NCLIENTS; cc++)
  524.   {
  525.     if (client[cc].active && (cc != server.client) && (c != cc) )
  526.     {
  527.       SendASCIIPacket (client[cc].socket, "GBYE %d %s",
  528.       c, target[client[c].target].name);
  529.     }
  530.   }
  531.  
  532.   /* Destroy associated target */
  533.   DestroyTarget (client[c].target);
  534.   #endif /* AMIGA */
  535. }
  536.  
  537. void QueuePositionReport()
  538. /*
  539.  *  Force our position to be sent
  540.  */
  541. {
  542.   int c;
  543.  
  544.   if (am_client)
  545.   {
  546.     clientme.timer.pos = CLIENTPOSINTERVAL;
  547.   }
  548.   else if (am_server)
  549.   {
  550.     for (c=0; c<NCLIENTS; c++)
  551.     {
  552.       client[c].timer.posn[server.client] = client[c].posninterval;
  553.     }
  554.   }
  555. }
  556.  
  557. int InitClientTarget()
  558. /*
  559.  *  Set up a target for a client
  560.  */
  561. {
  562.   int m, t;
  563.  
  564.   t = FindTarget();
  565.   target[t].age = 0.1;
  566.   strcpy (target[t].name, "Sparky");
  567.   target[t].invisible = 0;
  568.   target[t].hidden = 0;
  569.   target[t].model = m = LoadModel ("light2.tri");
  570.   target[t].list = model[m].list;
  571.   target[t].shieldregen = SHIELD_REGEN;
  572.  
  573.   return t;
  574. }
  575.  
  576. void NetHitTarget (int t, int m)
  577. /*
  578.  *  Target t was hit by missile m
  579.  */
  580. {
  581.   int c;
  582.  
  583.   if (!am_server) return;
  584.  
  585.   /* Find the client that belongs to this target */
  586.   c = FindClientByTarget (t);
  587.  
  588.   /* Don't bother if it's me */
  589.   if (c == server.client) return;
  590.  
  591.   /* Send them the packet */
  592.   if (client[c].active)
  593.   {
  594.     SendASCIIPacket (client[c].socket,
  595.     "MHIT %lf", weapon[msl[m].weapon].yield);
  596.  }
  597. }
  598.  
  599. void NetDestroyTarget (int t, int m)
  600. /*
  601.  *  Target t was destroyed by missile m
  602.  */
  603. {
  604.  int cvictim, ckiller;
  605.  
  606.  if (!am_server) return;
  607.  
  608.  /* Find the client that belongs to the victim */
  609.  cvictim = FindClientByTarget (t);
  610.  
  611.  /* Find the client that belongs to the killer */
  612.  ckiller = FindClientByTarget (msl[m].owner);
  613.  
  614.  /* Tell everyone */
  615.  NetDestroyClient (cvictim, ckiller);
  616. }
  617.  
  618. void NetDestroyClient (int cv, int ck)
  619. /*
  620.  *  Client cv was killed by client ck
  621.  */
  622. {
  623.  int c;
  624.  
  625.  /* Adjust frags */
  626.  client[ck].frags++;
  627.  
  628.  /* Tell everyone */
  629.  for (c=0; c<NCLIENTS; c++)
  630.  {
  631.   if (client[c].active && (c != server.client) )
  632.   {
  633.    SendASCIIPacket (client[c].socket, "MDIE %d %d", cv, ck);
  634.   }
  635.  }
  636.  
  637.  /* Tell me */
  638.  Cprint ("%s was killed by %s",
  639.   target[client[cv].target].name,
  640.   target[client[ck].target].name);
  641.  
  642.  /* Make client's target hidden */
  643.  if (cv != server.client) target[client[cv].target].hidden = 1;
  644.  
  645.  CheckLock();
  646. }
  647.  
  648. void NetTargetCratered (int t, int p)
  649. /*
  650.  *  Target t cratered on planet p
  651.  */
  652. {
  653.  int c, cc;
  654.  
  655.  /* Get client */
  656.  cc = FindClientByTarget (t);
  657.  
  658.  /* Adjust frags */
  659.  client[cc].frags--;
  660.  
  661.  /* Tell everyone */
  662.  for (c=0; c<NCLIENTS; c++)
  663.  {
  664.   if (client[c].active && (c != server.client) )
  665.   {
  666.    SendASCIIPacket (client[c].socket, "CRAT %d %d", cc, p);
  667.   }
  668.  }
  669.  
  670.  /* Tell me */
  671.  Cprint ("%s cratered on %s", target[t].name, planet[p].name);
  672.  
  673.  /* Hide target */
  674.  if (cc != server.client) target[t].hidden = 1;
  675.  
  676.  CheckLock();
  677.  
  678. int FindClientByTarget (int t)
  679. /*
  680.  *  Figure out what client belongs to this target
  681.  */
  682. {
  683.  int c;
  684.  
  685.  /* Is it me? */
  686.  if (t == (-1)) return server.client;
  687.  
  688.  /* Loop through clients */
  689.  for (c=0; c<NCLIENTS; c++)
  690.  {
  691.   if (client[c].active && (t==client[c].target) ) return c;
  692.  }
  693.  
  694.  /* When in doubt, make it me */
  695.  return server.client;
  696. }
  697.  
  698. void NetClientFires (int clnt, int wep)
  699. /*
  700.  *  Client clnt has fired weapon wep
  701.  */
  702. {
  703.  double v[3], d;
  704.  int c, t1, t2;
  705.  
  706.  if (!am_server) return;
  707.  
  708.  t1 = client[clnt].target;
  709.  
  710.  /* Loop through clients */
  711.  for (c=0; c<NCLIENTS; c++)
  712.  {
  713.   if (client[c].active && (c != clnt) && (c != server.client))
  714.   {
  715.    t2 = client[c].target;
  716.  
  717.    /* Find distance between clients */
  718.    Vsub (v, target[t1].pos, target[t2].pos);
  719.    d = Mag2 (v);
  720.  
  721.    /* Don't bother if too far */
  722.    if (d > TARG_MAXRANGE2) continue;
  723.  
  724.    /* Send packet */
  725.    SendASCIIPacket (client[c].socket,
  726.     "FIRE %d %d", clnt, wep);
  727.   }
  728.  }
  729. }
  730.  
  731. void NetPlayerDies()
  732. /*
  733.  *  We died in a network game
  734.  */
  735. {
  736.  double v[3];
  737.  int i;
  738.  
  739.  /* Change game state */
  740.  state = STATE_DEAD1;
  741.  
  742.  /* Set up timer */
  743.  player.dead_timer = DEAD_TIME;
  744.  
  745.  /* Stop Sparky */
  746.  player.vel[0] = player.vel[1] = player.vel[2] = 0.0;
  747.  
  748.  /* Assign new position */
  749.  do
  750.  {
  751.   for (i=0; i<3; i++) v[i] = player.pos[i] +
  752.    rnd(1000000.0/KM_TO_UNITS1) - 500000.0/KM_TO_UNITS1;
  753.  } while (!RespawnOkay(v));
  754.  Vset (player.pos, v);
  755.  
  756.  /* Give Zorkian message */
  757.  Mprint ("*** You have died ***");
  758.  
  759. int RespawnOkay (double *v)
  760. /* 
  761.  *  Check if respawn location is okay 
  762.  */ 
  763.  int p; 
  764.  double v1[3], d; 
  765.  
  766.  for (p=0; p<NPLANETS; p++) 
  767.  { 
  768.   if (!planet[p].hidden) 
  769.   { 
  770.    /* Compute range to planet */ 
  771.    Vsub (v1, planet[p].pos, v); 
  772.    d = Mag (v1); 
  773.  
  774.    /* Too close? */ 
  775.    if (d < 5.0 * planet[p].radius) return 0; 
  776.   } 
  777.  } 
  778.  
  779.  /* Okay if we got here */ 
  780.  return 1; 
  781. }
  782.  
  783. int FindEndian()
  784. /*
  785.  *  Try to figure out the endianness of this machine, especially with
  786.  *  regard to floats.  Kinda kludgy but it's been working great.
  787.  */
  788. {
  789.  union
  790.  {
  791.   unsigned char c[4];
  792.   float f;
  793.  } u;
  794.  
  795.  /* Assume one way */
  796.  endian = 0;
  797.  
  798.  /* Better have 4-byte floats or we're sunk */
  799.  if (4 != sizeof(float))
  800.  {
  801.   Mprint ("PANIC! This machine doesn't use 4-byte floats");
  802.   Log ("FindEndian: PANIC! This machine doesn't use 4-byte floats");
  803.   return 0;
  804.  }
  805.  
  806.  /* Set a float and pick apart the bytes to see if we
  807.     recognize the order */
  808.  u.f = 3141.59;
  809.  
  810.  /* Test one way */
  811.  if ( (u.c[0] == 0x45) && (u.c[1] == 0x44) &&
  812.       (u.c[2] == 0x59) && (u.c[3] == 0x71) )
  813.  {
  814.   /* Yay! It's MIPS, SPARC, RS/6000, HP or something
  815.      like that */
  816.   endian = 0;
  817.   return 1;
  818.  }
  819.  
  820.  /* Hmm, test other way */
  821.  if ( (u.c[0] == 0x71) && (u.c[1] == 0x59) &&
  822.       (u.c[2] == 0x44) && (u.c[3] == 0x45) )
  823.  {
  824.   /* Yay! Intel or DEC or something like that */
  825.   endian = 1;
  826.   return 1;
  827.  }
  828.  
  829.  /* Bad news, Sparky! */
  830.  Mprint ("Unrecognized floating point format! No network for you!");
  831.  Log ("FindEndian: Unrecognized floating point format");
  832.  
  833.  return 0;
  834. }
  835.  
  836. void EncFloat (double d, unsigned char *c)
  837. /*
  838.  *  Encode a double
  839.  */
  840. {
  841.  union
  842.  {
  843.   unsigned char c[4];
  844.   float f;
  845.  } u;
  846.  
  847.  /* Convert to float */
  848.  u.f = (float) d;
  849.  
  850.  /* Write bytes */
  851.  if (endian)
  852.  {
  853.   c[0] = u.c[0];
  854.   c[1] = u.c[1];
  855.   c[2] = u.c[2];
  856.   c[3] = u.c[3];
  857.  }
  858.  else
  859.  {
  860.   c[0] = u.c[3];
  861.   c[1] = u.c[2];
  862.   c[2] = u.c[1];
  863.   c[3] = u.c[0];
  864.  }
  865. }
  866.  
  867. double DecFloat (unsigned char *c)
  868. /*
  869.  *  Decode a float
  870.  */
  871. {
  872.  union
  873.  {
  874.   unsigned char c[4];
  875.   float f;
  876.  } u;
  877.  
  878.  /* Move into union */
  879.  if (endian)
  880.  {
  881.   u.c[0] = c[0];
  882.   u.c[1] = c[1];
  883.   u.c[2] = c[2];
  884.   u.c[3] = c[3];
  885.  }
  886.  else
  887.  {
  888.   u.c[3] = c[0];
  889.   u.c[2] = c[1];
  890.   u.c[1] = c[2];
  891.   u.c[0] = c[3];
  892.  }
  893.  
  894.  return (double) u.f;
  895. }
  896.  
  897. void EncVector (double *v, char *c)
  898. /*
  899.  *  Encode a whole vector
  900.  */
  901. {
  902.  EncFloat (v[0], &c[0]);
  903.  EncFloat (v[1], &c[4]);
  904.  EncFloat (v[2], &c[8]);
  905. }
  906.  
  907. void EncUnitVector (double *v, char *c)
  908. /*
  909.  *  Encode vector of unit floats
  910.  */
  911. {
  912.  c[0] = EncUnitFloat (v[0]);
  913.  c[1] = EncUnitFloat (v[1]);
  914.  c[2] = EncUnitFloat (v[2]);
  915. }
  916.  
  917. void DecVector (double *v, unsigned char *c)
  918. /*
  919.  *  Decode a whole vector
  920.  */
  921. {
  922.  v[0] = DecFloat (&c[0]);
  923.  v[1] = DecFloat (&c[4]);
  924.  v[2] = DecFloat (&c[8]);
  925. }
  926.  
  927. int EncUnitFloat (double d)
  928. /*
  929.  *  Convert double on [-1,1] to integer on [0,255]
  930.  */
  931. {
  932.  int i;
  933.  
  934.  if (d < -1.0) d = -1.0;
  935.  if (d >  1.0) d =  1.0;
  936.  
  937.  i = (int) ((d + 1.0) * 127.5);
  938.  
  939.  return i;
  940. }
  941.  
  942. double DecUnitFloat (unsigned char c)
  943. /*
  944.  *  Convert integer on [0,255] to double on [-1,1]
  945.  */
  946. {
  947.  double d;
  948.  int i;
  949.  
  950.  i = 0xff & c;
  951.  d = (((double) i) / 127.5) - 1.0;
  952.  
  953.  return d;
  954. }
  955.  
  956. void DecUnitVector (double *v, unsigned char *c)
  957. {
  958.  v[0] = DecUnitFloat (c[0]);
  959.  v[1] = DecUnitFloat (c[1]);
  960.  v[2] = DecUnitFloat (c[2]);
  961. }
  962.  
  963. void SendBinaryPacket (SOCKET socket, char *fmt, ...)
  964. /*
  965.  *  Send a binary packet
  966.  */
  967. {
  968.  int i, p, len;
  969.  unsigned char buf[256];
  970.  va_list ap;
  971.  
  972.  /* Start up varargs */
  973.  va_start (ap, fmt);
  974.  
  975.  p = 0;
  976.  len = strlen (fmt);
  977.  
  978.  /* Loop through format */
  979.  for (i=0; i<len; i++)
  980.  {
  981.   switch (fmt[i])
  982.   {
  983.   case 'c': /* Single character */
  984.    buf[p++] = va_arg (ap, int);
  985.    break;
  986.  
  987.   case 'F': /* Normal float */
  988.    EncFloat (va_arg (ap, double), &buf[p]);
  989.    p += 4;
  990.    break;
  991.  
  992.   case 'f': /* Unit float */
  993.    buf[p++] = EncUnitFloat (va_arg (ap, double));
  994.    break;
  995.  
  996.   case 'V': /* Normal vector */
  997.    EncVector (va_arg (ap, double *), &buf[p]);
  998.    p += 12;
  999.    break;
  1000.  
  1001.   case 'v': /* Unit vector */
  1002.    EncUnitVector (va_arg (ap, double *), &buf[p]);
  1003.    p += 3;
  1004.    break;
  1005.  
  1006.   default:
  1007.    Log ("SendBinaryPacket: Bad format character: %c", fmt[i]);
  1008.    break;
  1009.   }
  1010.  }
  1011.  
  1012.  va_end (ap);
  1013.  
  1014.  /* Send it off! */
  1015.  XmitBinaryPacket (socket, buf, p);
  1016.  xmit_bytes += 2 + p;
  1017. }
  1018.  
  1019. void DecodeBinaryPacket (char *pkt, char *fmt, ...)
  1020. /*
  1021.  *  Decode a binary packet
  1022.  */
  1023. {
  1024.  int i, p, len;
  1025.  va_list ap;
  1026.  double *d;
  1027.  
  1028.  /* Start up varargs */
  1029.  va_start (ap, fmt);
  1030.  
  1031.  len = strlen (fmt);
  1032.  p = 0;
  1033.  
  1034.  /* Loop through format */
  1035.  for (i=0; i<len; i++)
  1036.  {
  1037.   switch (fmt[i])
  1038.   {
  1039.   case 'c': /* Single character */
  1040.    *(va_arg (ap, int *)) = pkt[p];
  1041.    p++;
  1042.    break;
  1043.  
  1044.   case 'F': /* Normal float */
  1045.    *(va_arg (ap, double *)) = DecFloat (&pkt[p]);
  1046.    p += 4;
  1047.    break;
  1048.  
  1049.   case 'f': /* Unit float */
  1050.    *(va_arg (ap, double *)) = DecUnitFloat (pkt[p]);
  1051.    p++;
  1052.    break;
  1053.  
  1054.   case 'V': /* Normal vector */
  1055.    d = va_arg (ap, double *);
  1056.    DecVector (d, &pkt[p]);
  1057.    p += 12;
  1058.    break;
  1059.  
  1060.   case 'v': /* Unit vector */
  1061.    d = va_arg (ap, double *);
  1062.    DecUnitVector (d, &pkt[p]);
  1063.    p += 3;
  1064.    break;
  1065.  
  1066.   default:
  1067.    Log ("DecBinaryPacket: Bad format character: %c", fmt[i]);
  1068.    break;
  1069.   }
  1070.  }
  1071.  
  1072.  va_end (ap);
  1073. }
  1074.